<?php

declare(strict_types=1);

namespace Service\WebSocketService;
use Service\BaseService;
use Service\Code\Normal;
use App\Model\BbcModel\ManagerChannel;
use App\Model\BbcModel\ManagerChannelLog;
use PhpOffice\PhpSpreadsheet\IOFactory;

/**
 * web socket 中间校验类
 * @author chenshubo
 */
class BaseWsService extends BaseService
{
    const USER_LOGIN_CACHE_KEY = 'channel_user_login_cache_';
    
    /**
     * 业务中间类
     * @param $server
     * @param $frame
     */
    public function receiveMessage($server,$frame)
    {
        $message = @json_decode($frame->data,true);
        $fd      = $frame->fd;
        if( empty($message['token']) ) {
            $send = Normal::returnCode(Normal::WS_ERROR,"token参数不能为空");
            return $server->push($fd,json_encode($send,JSON_UNESCAPED_UNICODE));
        }
        
        $manager_id = $this->getUserByLoginToken($message['token']);
        if( empty($manager_id) ) {
            $send = Normal::returnCode(Normal::WS_ERROR,"当前token无效，请重新输入验证!");
            return $server->push($fd,json_encode($send,JSON_UNESCAPED_UNICODE));
        }
        
        //通过管理员id获取 cid
        $manager_info = ManagerChannel::instance()->info(['id'=>$manager_id]);
        $clientInfo = $server->getClientInfo($fd);
        
        //开始校验参数
        $result = $this->checkWsParameters($message);
        if( $result['code'] != Normal::SUC )
        {
            $log = [
                'manager_id'    => $manager_id,
                'manager_name'  => $manager_info['name'],
                'content'       => json_encode($message,JSON_UNESCAPED_UNICODE),
                'ip'            => $clientInfo['remote_ip'],
                'url'           => $clientInfo['remote_ip'],
            ];
            ManagerChannelLog::instance()->addLog($log);
            $result['code'] = Normal::WS_ERROR;
            return $server->push($fd,json_encode($result,JSON_UNESCAPED_UNICODE));
        }
        

        $class  = $result['data']['class'];
        $method = $result['data']['method'];
        $body   = $result['data']['body'];
        $return = $class::instance()->{$method}($server,$fd,$body,(int)$manager_id,(int)$manager_info['cid']);
        $log = [
            'manager_id'    => $manager_id,
            'manager_name'  => $manager_info['name'],
            'content'       => json_encode([
                'request'   => $message,
                'response'  => $return
            ],JSON_UNESCAPED_UNICODE),
            'ip'            => $clientInfo['remote_ip'],
            'url'           => $clientInfo['remote_ip'],
        ];
        ManagerChannelLog::instance()->addLog($log);
        return $server->push($frame->fd,json_encode($return,JSON_UNESCAPED_UNICODE));
    }
    
    /**
     * 校验参数
     * @param array $message
     * @return mixed
     */
    protected function checkWsParameters(array $message)
    {
        if( empty($message['method']) ) {
            return Normal::returnCode(Normal::FAIL,"method参数不能为空");
        }
        
        if( !isset($message['body']) ) {
            return Normal::returnCode(Normal::FAIL,"body参数不能为空");
        }
        
        $body = $message['body'];
        //判断和校验文件
        if( isset($body['isUploadFile']) && $body['isUploadFile'] == true && empty($body['fileUrl'])) {
            return Normal::returnCode(Normal::FAIL,"body.fileUrl参数不能为空,可以从接口/common/upload/uploadLocalFile上传文件");
        }
        
        //判断和校验文件
        if( isset($body['isUploadFile']) && $body['isUploadFile'] == true && !empty($body['fileUrl'])) 
        {
            $result_upload = self::getExcelData($body['fileUrl']);
            if( $result_upload['code'] != Normal::SUC ) {
                return $result_upload;
            }
            $message['body']['upLoadData'] = $result_upload['data'];
        }
        
        $methods = \explode(".",$message['method']);
        $methods = array_filter($methods);
        if( count($methods) != 2 ) {
            return Normal::returnCode(Normal::FAIL,"method格式解析错误，请核对!");
        }
        $class = "Service\\WebSocketService\\{$methods[0]}";
        if( !class_exists($class) ) {
            return Normal::returnCode(Normal::FAIL,"实体业务类【{$class}】不存在!");
        }
        
        $method = $methods[1];
        if( !method_exists($class, $method)) {
            return Normal::returnCode(Normal::FAIL,"实体业务类【{$class}】下方法【{$method}】不存在!");
        }
        return Normal::returnCode(Normal::SUC,"校验完成",[
            'class'     => $class,
            'method'    => $method,
            'body'      => $message['body']
        ]);
    }
    
    /**
     * 读取文件内容
     * @param string $fileUrl
     */
    private function getExcelData(string $fileUrl)
    {
        try {
            $pathInfos  = pathinfo($fileUrl);
            $ext        = $pathInfos['extension'];
            //开始处理数据资源
            $contents   = file_get_contents($fileUrl);
            $file       = __DIR__.'/'.date("YmdHis").rand(100000,999999).'.'.$ext;
            file_put_contents($file,$contents);
            
            //读取excel数据
            $objReader      = IOFactory::createReader(ucfirst($ext));
            //自动获取文件类型
            $file_type      = IOFactory::identify($file);
            //打开文件、载入excel表格
            $spreadsheet    = $objReader->load($file);
            // 获取活动工作薄
            $sheet          = $spreadsheet->getActiveSheet();
            //获取所有内容并转化为数组
            $data           = $sheet->toArray();
            unlink($file);
            return Normal::returnCode(Normal::SUC,"数据读取成功",$data);
        } catch ( \Throwable $th ) {
            return Normal::returnCode(Normal::FAIL,"数据获取失败【{$th->getMessage()}】");
        }
    }
    
    /**
     * 根据token获取数据
     * @param string $token
     * @return mixed
     */
    protected function getUserByLoginToken(string $token)
    {
        $redis = redis();
        return $redis->get(self::USER_LOGIN_CACHE_KEY.$token);
    }
}